#============================================================
#	Editor Node
#============================================================
#  获取 Godot 编辑器上的节点
# * 使用 AssetLib 中的 Editor Debugger 插件帮助下进行查找到的节点
#============================================================
# @datetime: 2022-5-13 18:38:57
#============================================================
tool
class_name GDEditorNode
extends EditorScript

var _plugin: EditorPlugin = EditorPlugin.new()


# ScriptEdior 菜单操作，部分功能不能使用
# 详见：https://github.com/godotengine/godot/blob/master/editor/plugins/script_editor_plugin.h
enum {
	FILE_NEW,
	FILE_NEW_TEXTFILE,
	FILE_OPEN,
	FILE_REOPEN_CLOSED,
	FILE_OPEN_RECENT,
	FILE_SAVE,
	FILE_SAVE_AS,
	FILE_SAVE_ALL,
	FILE_THEME,
	FILE_RUN,
	FILE_CLOSE,
	CLOSE_DOCS,
	CLOSE_ALL,
	CLOSE_OTHER_TABS,
	TOGGLE_SCRIPTS_PANEL,
	SHOW_IN_FILE_SYSTEM,
	FILE_COPY_PATH,
	FILE_TOOL_RELOAD,
	FILE_TOOL_RELOAD_SOFT,
	SEARCH_IN_FILES,
	REPLACE_IN_FILES,
	SEARCH_HELP,
	SEARCH_WEBSITE,
	HELP_SEARCH_FIND,
	HELP_SEARCH_FIND_NEXT,
	HELP_SEARCH_FIND_PREVIOUS,
	WINDOW_MOVE_UP,
	WINDOW_MOVE_DOWN,
	WINDOW_NEXT,
	WINDOW_PREV,
	WINDOW_SORT,
	WINDOW_SELECT_BASE = 100
}


# Godot 编辑器左上角菜单按钮容器
var editor_menu_container: HBoxContainer
# 视图切换容器
var view_change_container : Control
# 顶部容器
var top_container : Control
# 底部容器
var bottom_container : Control


var menu_scene
var menu_project
var menu_debug
var menu_editor
var menu_help

var tool_button_2d: ToolButton
var tool_button_3d: ToolButton
var tool_button_script: ToolButton
var tool_button_assetLib: ToolButton

var tool_run: ToolButton
var tool_pause: ToolButton
var tool_stop: ToolButton
var tool_run_current
var tool_run_custom: ToolButton

var opened_scene_tabs : Tabs
var focus_mode_button : ToolButton

# 2D 编辑区
var canvas_item_editor : Control
# 3D 编辑区
var spatial_editor : Control
# 脚本编辑区
var script_editor : ScriptEditor

# 2D 工具栏按钮容器
var canvas_item_tool_button_container : Control
# 3D 工具栏按钮容器
var spatial_tool_button_container : Control

var editor_sub_panel : Array = []

# 场景树 Docker
var scene_tree_docker
var create_node_dialog : ConfirmationDialog
var create_node_search_line_edit : LineEdit
var create_node_tree : Tree

var find_files_dialog : WindowDialog
var script_create_dialog : WindowDialog
var editor_file_dialog : WindowDialog
var editor_help_search : WindowDialog


var script_menu_container : Control	# 脚本编辑区菜单列表
var script_text_editor_container : TabContainer # 脚本编辑容器
var script_item_list : ItemList	# 脚本编辑区左侧打开的脚本和文档项列表
var filter_script_line_edit : LineEdit	# 过滤 script_item_list 项
var script_menu_file : MenuButton
var script_menu_search : MenuButton
var script_menu_debug: MenuButton


func get_editor_interface() -> EditorInterface:
	return _plugin.get_editor_interface()

func get_tree() -> SceneTree:
	return get_editor_interface().get_tree()


const META_KEY = "@Meta_GodotEngine_Editor_Nodes"



func _init():
	# 整个 Godot 游戏编辑面板
	var editor_panel : Panel = get_editor_interface() \
		.get_base_control()
	
	var editor_container = editor_panel.get_child(0)
	if not editor_container is VBoxContainer:
		editor_container = editor_panel.get_child(1)
	
	for child in editor_container.get_children():
		if child is HBoxContainer:
			# 上部分（编辑器菜单，视图切换，运行场景）
			top_container = child
	
	# 编辑器菜单（场景，项目，调试等菜单容器）
	editor_menu_container = top_container.get_child(0)
	menu_scene = editor_menu_container.get_child(0)
	menu_project = editor_menu_container.get_child(1)
	menu_debug = editor_menu_container.get_child(2)
	menu_editor = editor_menu_container.get_child(3)
	menu_help = editor_menu_container.get_child(4)
	
	# 视图切换
	view_change_container = top_container.get_child(2)
	while view_change_container == null:
		view_change_container = top_container.get_child(2)
		print(top_container.get_parent())
		yield(get_tree().create_timer(0.1), "timeout")
	
	tool_button_2d = view_change_container.get_child(0)
	tool_button_3d = view_change_container.get_child(1)
	tool_button_script = view_change_container.get_child(2)
	tool_button_assetLib = view_change_container.get_child(3)
	
#	click_button(tool_button_2d)
	
	# 运行场景按钮
	var run_scene_container = top_container.get_child(4)
	tool_run = run_scene_container.get_child(0)
	tool_pause = run_scene_container.get_child(1)
	tool_stop = run_scene_container.get_child(2)
	tool_run_current = run_scene_container.get_child(3)
	tool_run_custom = run_scene_container.get_child(4)
	
	# 下部分（各个功能面板，场景编辑，文件系统，场景树，属性检查器等）
	bottom_container = top_container.get_parent().get_child(top_container.get_index() + 1)
	
	# 一共五部分
	editor_sub_panel.clear()
	editor_sub_panel.resize(5)
	editor_sub_panel[0] = bottom_container.get_child(0)
	editor_sub_panel[1] = editor_sub_panel[0].get_parent().get_child(1).get_child(0)
	editor_sub_panel[2] = editor_sub_panel[1].get_parent().get_child(1).get_child(0)
	editor_sub_panel[3] = editor_sub_panel[2].get_parent().get_child(1).get_child(0)
	editor_sub_panel[4] = editor_sub_panel[3].get_parent().get_child(1)
	
	# 左侧
	# 场景树
	scene_tree_docker = editor_sub_panel[1].get_child(0).get_child(0)
	for sub_panel in editor_sub_panel:
		scene_tree_docker = find_class_node(sub_panel, "SceneTreeDock")
		if scene_tree_docker:
			break
	
	# 创建节点弹窗
	create_node_dialog = find_class_node(scene_tree_docker, "CreateDialog")
	var create_node_dialog_ok : Button = create_node_dialog.get_child(2).get_child(1)
	var create_node_dialog_cancel : Button = create_node_dialog.get_child(2).get_child(3)
	var search_container = create_node_dialog.get_child(3).get_child(1)
	create_node_search_line_edit = search_container.get_child(1).get_child(0).get_child(0)
	create_node_tree = create_node_dialog.get_child(3).get_child(1).get_child(3).get_child(0)
	
	# 中间的部分
	var middle_sub_panel_container = editor_sub_panel[2].get_child(0)
	# 中间主要编辑器部分
	var major_container = middle_sub_panel_container.get_child(0)
	# 中间底部输出部分
	var output_panel = middle_sub_panel_container.get_child(1)
	
	var middle_tab_container = major_container.get_child(0).get_child(0)
	# 打开的场景的Tab页
	opened_scene_tabs = middle_tab_container.get_child(1)
	# 中间专注模式按钮
	focus_mode_button = middle_tab_container.get_child(2)
	
	# 中间的编辑区
	var middle_editor_container = major_container.get_child(0).get_child(1).get_child(0)
	# 2D 编辑区
	canvas_item_editor = middle_editor_container.get_child(0)
	# 3D 编辑区
	spatial_editor = middle_editor_container.get_child(1)
	# 脚本编辑区
	script_editor= middle_editor_container.get_child(2)
	# 资源库
	var asset_library = middle_editor_container.get_child(3)
	
	# 2D 工具按钮列表
	canvas_item_tool_button_container = canvas_item_editor.get_child(0)
	# 3D 工具按钮列表
	spatial_tool_button_container = spatial_editor.get_child(0)
	
	var data = {}
	for i in script_editor.get_children():
		# 通过类名获取其中的几个唯一的特殊的类的节点
		data[i.get_class()] = i
	find_files_dialog = data['FindInFilesDialog']
	script_create_dialog = data['ScriptCreateDialog']
	editor_file_dialog = data['EditorFileDialog']
	editor_help_search = data['EditorHelpSearch']
	
#	script_create_dialog.popup()
	
	var script_editor_container = script_editor.get_child(0)
	# 脚本菜单工具按钮列表（其中有部分不是按钮，而是其他代码编辑框的菜单容器）
	script_menu_container = script_editor_container.get_child(0)
	
	# 脚本编辑区左侧
	var script_editor_left = script_editor_container.get_child(1).get_child(0)
	# 脚本编辑区右侧（子节点对应左侧打开的脚本）
	var script_editor_right = script_editor_container.get_child(1).get_child(1)
	script_text_editor_container = script_editor_right
	
	var script_item_list_container = script_editor_left.get_child(0)
	filter_script_line_edit = script_item_list_container.get_child(0)
	script_item_list = script_item_list_container.get_child(1) as ItemList
	
	# 脚本编辑器菜单列表（编辑和转到两个菜单是每个代码编辑框独立的）
	for child in script_menu_container.get_children():
		if child is MenuButton:
			match child.text:
				"File", "文件":
					script_menu_file = child
				"Search", "搜索":
					script_menu_search = child
				"Debug", "调试":
					script_menu_debug = child


##  获取左侧的脚本 ItemList 的数据
## @index  索引
## @return  
func get_script_item_data(index: int) -> Dictionary:
	return {
		"name": script_item_list.get_item_text(index), 
		"path": script_item_list.get_item_tooltip(index),
		"tab": script_item_list.get_item_metadata(index),
		# 如果刚打开这个项目，这个脚本从未被打开过
		# 那么他就还没有 CodeEditor 节点，它是一种懒加载的方式
		# 只有在打开了这个脚本，才会添加它的 CodeEditor
		"code_text_editor": get_code_text_editor(
			script_text_editor_container.get_child(script_item_list.get_item_metadata(index))
		),
	}


##  获取当前正在编辑的代码文本框
## @return  
func get_current_code_text_editor() -> TextEdit:
	var current_script_editor = script_text_editor_container.get_child(script_text_editor_container.current_tab)
	return get_code_text_editor(current_script_editor)


##  获取对应的 ScriptEditor 的 CodeEditor
## @script_editor_or_index_or_path  
func get_code_text_editor(script_editor_or_index_or_path):
	if script_editor_or_index_or_path is Control:
		if script_editor_or_index_or_path.get_child_count() == 0:
			return null
		var current_code_editor = script_editor_or_index_or_path.get_child(0).get_child(0)
		var current_code_text_editor : TextEdit = current_code_editor.get_child(0)
		return current_code_text_editor
	elif script_editor_or_index_or_path is int:
		return get_code_text_editor(script_text_editor_container.get_child(script_editor_or_index_or_path))
	elif script_editor_or_index_or_path is String:
		# 存在文件时则遍历
		if ResourceLoader.exists(script_editor_or_index_or_path):
			for i in script_item_list.get_item_count():
				var path = script_item_list.get_item_tooltip(i)
				if path == script_editor_or_index_or_path:
					return get_code_text_editor(i)
		else:
			# 按照显示的 item 名称搜索
			for i in script_item_list.get_item_count():
				var path = script_item_list.get_item_text(i)
				if path == script_editor_or_index_or_path:
					return get_code_text_editor(i)
	return null


##  找到这个类名的节点
## @parent  父节点
## @_class  类名
## @return  返回找到的节点
func find_class_node(parent: Node, _class: String) -> Node:
	for child in parent.get_children():
		if child.get_class() == _class:
			return child
	for child in parent.get_children():
		var node = find_class_node(child, _class)
		if node:
			return node
	return null


##  点击按钮
## @button  
func click_button(button: BaseButton):
	button.emit_signal("pressed")


##  点击菜单按钮项 
## @menu_button  要点击的菜单按钮
## @menu  菜单id值，或菜单名
func click_menu_button_item(menu_button: MenuButton, menu):
	var popup : PopupMenu = menu_button.get_popup()
	if menu is String and menu.is_valid_integer():
		menu = int(menu)
	
	# 是一个数字的话执行
	if menu is int:
		var id = int(menu)
		popup.emit_signal("id_pressed", id)
	elif menu is String:
		for id in popup.get_item_count():
			var text = popup.get_item_text(id)
			if text == menu:
				popup.emit_signal("id_pressed", id)
				break
	else:
		printerr("菜单名类型错误")


##  点击脚本菜单项
func click_script_menu(item: int):
	# 脚本编辑器菜单操作
	script_editor._menu_option(item)


##  弹窗搜索筛选
## @node_name  搜索的节点名称
func popup_create_node_dialog(node_name: String = ""):
	create_node_dialog.popup()
	create_node_search_line_edit.text = node_name
	create_node_search_line_edit.emit_signal("text_changed", create_node_search_line_edit.text)


##  重新加载所有脚本
func reload_scripts():
	script_editor._reload_scripts()

##  创建编辑器菜单
## @name  菜单名称
## @return  返回创建的菜单按钮
func create_editor_menu(name: String) -> MenuButton:
	var tool_button = MenuButton.new()
	tool_button.text = name
	editor_menu_container.add_child(tool_button)
	return tool_button

##  创建脚本菜单按钮 
## @name  按钮名称
## @return  返回创建的菜单按钮
func create_script_menu(name: String) -> MenuButton:
	var tool_button = MenuButton.new()
	tool_button.text = name
	script_menu_container.add_child(tool_button)
	# 移动到前面的菜单的位置
	script_menu_container.move_child(
		tool_button, 
		script_menu_container.get_child_count() - 10
	)
	return tool_button


##  创建视图切换按钮
func create_view_button(name: String) -> ToolButton:
	var tool_button = ToolButton.new()
	tool_button.text = name
	view_change_container.add_child(tool_button)
	return tool_button


##  创建弹出菜单
## @return  
func create_popup_menu(items: PoolStringArray, icons: Array = []) -> PopupMenu:
	var popup = PopupMenu.new()
	var sep_char = "-"
	var idx = 0
	for item in items:
		if not item.begins_with(sep_char):
			if (idx < icons.size() 
				and icons[idx] is Texture
			):
				popup.add_icon_item(icons[idx], item)
			else:
				popup.add_item(item)
		else:
			# 清除两边的分隔符
			while true:
				if item.ends_with(sep_char) or item.begins_with(sep_char):
					item.trim_prefix(sep_char).trim_suffix(sep_char)
				else:
					break
			popup.add_separator(item)
		idx += 1
	get_editor_interface() \
		.get_editor_viewport() \
		.add_child(popup)
	return popup


##  返回代码编辑框光标位置
## @return  
func get_code_text_editor_cursor_pos() -> Vector2:
	var textedit : TextEdit = get_current_code_text_editor()
	var column : int = textedit.cursor_get_column()
	var line : int = textedit.cursor_get_line()
	var rect : Rect2 = textedit.get_rect_at_line_column(line, column-1)
	return (textedit.rect_global_position 
		+ rect.position
		+ Vector2(16, textedit.get_line_height())
	) 


#============================================================
#   测试
#============================================================

func _run():
	pass
	
	print("test")
	
	return
	
	var tab_container : TabContainer = editor_sub_panel[0].get_child(0)
	var side_bar = TabContainerSideBar.new()
	side_bar.set_tab_container(tab_container)
	get_editor_interface().get_viewport().add_child(side_bar)
	side_bar.change_to_fold_button()
	
	yield(get_editor_interface().get_tree().create_timer(10), "timeout")
	
	side_bar.restore()



func test01():
	var button = create_popup_menu(["test", "1", "2", "3"], [
		preload('res://icon.png')
	])
	button.rect_global_position = get_code_text_editor_cursor_pos()
	button.popup()
	
	yield(get_editor_interface().get_tree().create_timer(1), "timeout")
	button.queue_free()
	print("over")
#	click_script_menu(SHOW_IN_FILE_SYSTEM)

